import pyNastran
from pyNastran.bdf.bdf import BDF
from pyNastran.bdf.cards.materials import (
    MAT1,
    MAT2,
    MAT3,
    MAT4,
    MAT5,
    MAT8,
    MAT9,
    MAT10,
    MAT11,
    MATG,
    MATHE,
)
from pyNastran.bdf.cards.properties.shell import PSHELL
from pyNastran.bdf.cards.loads.static_loads import FORCE


"""
1. material extract common field
2. property only support thickness of PSHELL
3. load only support magnitude of FORCE
"""


def bdf_parser(bdf_file):
    # read bdf
    bdf = BDF(debug=False)
    bdf.read_bdf(bdf_file)
    # extract material parameters
    mat_parameters = []
    mat_class_mapping = {
        "MAT1": MAT1,
        "MAT2": MAT2,
        "MAT3": MAT3,
        "MAT4": MAT4,
        "MAT5": MAT5,
        "MAT8": MAT8,
        "MAT9": MAT9,
        "MAT10": MAT10,
        "MAT11": MAT11,
        "MATG": MATG,
        "MATHE": MATHE,
    }
    for id in bdf.material_ids:
        mat = bdf.Material(id)
        fields = mat.raw_fields()
        if fields[0] not in list(mat_class_mapping.keys()):
            print(f"not support {fields[0]}")
            continue
        maps = getattr(mat_class_mapping[fields[0]], "_field_map")
        for index, item in enumerate(fields):
            if index > 1:
                mat_parameters.append(
                    {
                        "name": f"{maps[index]}_{fields[0]}_{fields[1]}",
                        "mdoLabel": f"{maps[index]}_{fields[0]}_{fields[1]}",
                        "value": item,
                        "type": "number",
                    }
                )
    # extract property parameters
    prop_parameters = []
    for id in bdf.property_ids:
        prop = bdf.Property(id)
        fields = prop.raw_fields()
        if fields[0] == "PSHELL":
            # only support PSHELL
            maps = getattr(PSHELL, "_field_map")
            for index, item in enumerate(fields):
                if index == 3:
                    # only extract T
                    prop_parameters.append(
                        {
                            "name": f"{maps[index]}_{fields[0]}_{fields[1]}_{fields[2]}",
                            "mdoLabel": f"{maps[index]}_{fields[0]}_{fields[1]}_{fields[2]}",
                            "value": item,
                            "type": "number",
                        }
                    )
        else:
            print(f"not support {fields[0]}")
            continue
    # extract load parameters
    loads = bdf.loads  # key为sid value为对应的载荷数组
    load_parameters = []

    for _, v in loads.items():
        for force in v:
            fields = force.raw_fields()
            if fields[0] == "FORCE":
                # only support FORCE MAGNITUDE
                load_parameters.append(
                    {
                        "name": f"MAG_{fields[0]}_{fields[1]}_{fields[2]}",
                        "mdoLabel": f"MAG_{fields[0]}_{fields[1]}_{fields[2]}",
                        "value": fields[4],
                        "type": "number",
                    }
                )
            else:
                print(f"not support {fields[0]}")
                break
    return mat_parameters + prop_parameters + load_parameters


def filter_bdf(bdf_path):
    # 删除bdf文件存在的ENDDATA行,pyNastran不支持
    with open(bdf_path, "r") as file:
        data = file.readlines()
    new_data = [line for line in data if "ENDDATA" not in line]
    with open(bdf_path, "w") as file:
        file.writelines(new_data)


def update_bdf(bdf_path, parameters):
    model = BDF(debug=False)
    model.read_bdf(bdf_path)
    mat_class_mapping = {
        "MAT1": MAT1,
        "MAT2": MAT2,
        "MAT3": MAT3,
        "MAT4": MAT4,
        "MAT5": MAT5,
        "MAT8": MAT8,
        "MAT9": MAT9,
        "MAT10": MAT10,
        "MAT11": MAT11,
        "MATG": MATG,
        "MATHE": MATHE,
    }
    for parameter in parameters:
        # find field_name at field_list index
        if "MAT" in parameter["name"]:
            field_name, card_name, icard = parameter["name"].split("_")
            icard = int(icard)
            value = float(parameter["value"])
            maps = getattr(mat_class_mapping[card_name], "_field_map")
            for k, v in maps.items():
                if v == field_name:
                    index = k
                    break
        elif "PSHELL" in parameter["name"]:
            field_name, card_name, icard, _ = parameter["name"].split("_")
            icard = int(icard)
            index = 3
        elif "FORCE" in parameter["name"]:
            print(f"unsupport card_name {parameter['name']}")
        else:
            print(f"unsupport card_name {parameter['name']}")
        # update card
        model.update_card(card_name, icard, index, value)
    model.write_bdf(bdf_path)
